﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Microsoft.Win32;

namespace RoketPack.Management.Detection
{
    class Condition
    {
        /// <summary>
        /// A type enumeration representing the type of installation condition.
        /// </summary>
        internal enum ConditionType
        {
            FileExists,
            FolderExists,
            RegistryExists
        }

        private ConditionType p_Type;
        private string p_Value;

        /// <summary>
        /// Constructs a new installation condition with the specified type and value.
        /// </summary>
        /// <param name="type">The type of the condition.</param>
        /// <param name="value">The string value for the condition.</param>
        internal Condition(ConditionType type, string value)
        {
            this.p_Type = type;
            this.p_Value = value;
        }

        /// <summary>
        /// The type of the installation condition.
        /// </summary>
        internal ConditionType Type
        {
            get
            {
                return this.p_Type;
            }
        }

        /// <summary>
        /// The raw string value of the installation condition (with no special variable evaluation).
        /// </summary>
        internal string RawValue
        {
            get
            {
                return this.p_Value;
            }
        }

        /// <summary>
        /// The string value of the installation condition with special variables evaluated.
        /// </summary>
        internal string Value
        {
            get
            {
                return PathTranslator.Parse(this.p_Value);
            }
        }

        /// <summary>
        /// Returns whether the installation condition currently exists on the computer.
        /// </summary>
        /// <returns>Whether the installation condition currently exists on the computer.</returns>
        internal bool Matched()
        {
            switch (this.p_Type)
            {
                case ConditionType.FileExists:
                    return (File.Exists(this.Value));
                case ConditionType.FolderExists:
                    return (Directory.Exists(this.Value));
                case ConditionType.RegistryExists:
                    RegistryKey key = null;
                    string value = this.p_Value;
                    if (value.StartsWith("HKEY_CLASSES_ROOT\\"))
                    {
                        value = value.Substring("HKEY_CLASSES_ROOT\\".Length);
                        key = Registry.ClassesRoot;
                    }
                    else if (value.StartsWith("HKEY_CURRENT_USER\\"))
                    {
                        value = value.Substring("HKEY_CURRENT_USER\\".Length);
                        key = Registry.CurrentUser;
                    }
                    else if (value.StartsWith("HKEY_LOCAL_MACHINE\\"))
                    {
                        value = value.Substring("HKEY_LOCAL_MACHINE\\".Length);
                        key = Registry.LocalMachine;
                    }
                    else if (value.StartsWith("HKEY_USERS\\"))
                    {
                        value = value.Substring("HKEY_USERS\\".Length);
                        key = Registry.Users;
                    }
                    else if (value.StartsWith("HKEY_CURRENT_CONFIG\\"))
                    {
                        value = value.Substring("HKEY_CURRENT_CONFIG\\".Length);
                        key = Registry.CurrentConfig;
                    }

                    string[] regcomponents = value.Split('\\');
                    foreach (string r in regcomponents)
                    {
                        RegistryKey nkey = key.OpenSubKey(r);
                        key.Close();
                        key = nkey;

                        if (key == null)
                            return false;
                    }

                    return true;
            }

            return false;
        }
    }
}
